I was able to "revive" the event builder by basically just using the correct flags:
cd $GM2DAQ_DIR/eventbuilder make clean make
cd $GM2DAQ_DIR/eventbuilder
make clean
make
./mevb -e DAQ -b BUF
./mevb -e DAQ -b BUF
-b BUF
is important. Basically it looks for frontends that write to anything that begin with BUF
, so our AMC13001, AMC13002, and MasterGM2 write to BUF001, BUF002, and BUF respectively so they all get compounded into the event builder.screen -dmS event_builder $GM2DAQ_DIR/eventbuilder/mevb -e DAQ -b BUF
screen -dmS event_builder $GM2DAQ_DIR/eventbuilder/mevb -e DAQ -b BUF
SYSTEM
buffer (the buffer name can be changed in ebuser.cpp if you'd like):$MIDASSYS/bin/mdump -z SYSTEM
$MIDASSYS/bin/mdump -z SYSTEM
Now all the data will be logged if the logger is set to log the system buffer.
Note:
At one point I tried changing the ODB setting /Equipment/EB/Settings/User build
to yes. This broke things, keep it at no.
I noticed you will get CCC run abort errors if you try to start the 1 crate system with FC7 SFP ports enabled to talk to more than the one crate you have connected.
According to this link: https://daq00.triumf.ca/MidasWiki/index.php/MIDAS_Event_Construction
Midas bank names can only be 4 characters.We were trying to make them 5, I'm not sure if this is problematic for Lawrence's software.
To move files using an SSH tunnel:
In one terminal:
ssh -L 2222:10.0.0.3:22 pioneer@10.47.95.44
ssh -L 2222:10.0.0.3:22 pioneer@10.47.95.44
Then:
scp -P 2222 root@localhost:{file to copy} {destination}
scp -P 2222 root@localhost:{file to copy} {destination}
similarly you can reverse the last command to move files.
I was able to get interrupt triggering to "work" by adding some things.
To CaloReadoutAMC13/frontend.cpp
//function pointer to the interrupt routine #define USE_INTERRUPT #ifdef USE_INTERRUPT void (*interrupt_routine)(void); #endif
//function pointer to the interrupt routine
#define USE_INTERRUPT
#ifdef USE_INTERRUPT
void (*interrupt_routine)(void);
#endif
EQUIPMENT equipment[] = { { "AMC13%03d", /* equipment name */ {1, 0xffff, /* event ID, trigger mask */ "BUF%03d", /* event buffer */ #ifdef USE_INTERRUPT EQ_INTERRUPT | EQ_EB, /* equipment type */ #else EQ_POLLED | EQ_EB, /* equipment type */ #endif LAM_SOURCE(0, 0xFFFFFF), /* event source crate 0, all stations */ "MIDAS", /* format */ TRUE, /* enabled */ RO_RUNNING , /* read only when running and end of run */ 10, /* poll for 1ms */ 0, /* stop run after this event limit */ 0, /* number of sub events */ 0, /* don't log history */ "", "", "", /* frontend host, frontend name, frontend file name */ "", "", FALSE}, /* status, status color, hidden */ read_trigger_event, /* readout routine */ }, {""} };
EQUIPMENT equipment[] = {
{
"AMC13%03d", /* equipment name */
{1, 0xffff, /* event ID, trigger mask */
"BUF%03d", /* event buffer */
#ifdef USE_INTERRUPT
EQ_INTERRUPT | EQ_EB, /* equipment type */
#else
EQ_POLLED | EQ_EB, /* equipment type */
#endif
LAM_SOURCE(0, 0xFFFFFF), /* event source crate 0, all stations */
"MIDAS", /* format */
TRUE, /* enabled */
RO_RUNNING , /* read only when running and end of run */
10, /* poll for 1ms */
0, /* stop run after this event limit */
0, /* number of sub events */
0, /* don't log history */
"", "", "", /* frontend host, frontend name, frontend file name */
"", "", FALSE}, /* status, status color, hidden */
read_trigger_event, /* readout routine */
},
{""}
};
Above is justt a "switch" to turn on and off interrupt
INT interrupt_configure(INT cmd, INT source __attribute__((unused)), POINTER_T adr __attribute__((unused))) { switch (cmd) { case CMD_INTERRUPT_ENABLE: break; case CMD_INTERRUPT_DISABLE: break; case CMD_INTERRUPT_ATTACH: interrupt_routine = (void (*)())adr; break; case CMD_INTERRUPT_DETACH: break; }
INT interrupt_configure(INT cmd, INT source __attribute__((unused)), POINTER_T adr __attribute__((unused)))
{
switch (cmd) {
case CMD_INTERRUPT_ENABLE:
break;
case CMD_INTERRUPT_DISABLE:
break;
case CMD_INTERRUPT_ATTACH:
interrupt_routine = (void (*)())adr;
break;
case CMD_INTERRUPT_DETACH:
break;
}
I think this is some midas function that somehow links interrupt_routine to read_trigger_event? I'm not sure, I more or less copied it from the master frontend.cpp.
BOOL send_interrupt_signal() { //std::cout << "Received interrupt signal" << std::endl; #ifdef USE_INTERRUPT (*interrupt_routine)(); #endif return TRUE; }
BOOL send_interrupt_signal()
{
//std::cout << "Received interrupt signal" << std::endl;
#ifdef USE_INTERRUPT
(*interrupt_routine)();
#endif
return TRUE;
}
The actual "signal" used by gpu_thread.cpp
frontend.h
extern void (*interrupt_routine)(void); // Declare the interrupt routine as extern // Function prototypes BOOL send_interrupt_signal();
extern void (*interrupt_routine)(void); // Declare the interrupt routine as extern
// Function prototypes
BOOL send_interrupt_signal();
Needed to give gpu_thread.cpp a way to send the interupt signal so it just includes this header file.
gpu_thread.cpp
send_interrupt_signal(); } // while (1)
send_interrupt_signal();
} // while (1)
If the gpu_thread gets to the end of it's while loop it sends an interrupt signal.
This seems to work for low rates (tested 20 Hz and 200 Hz). But the TCP buffer fills up immediately once I try 1000Hz. Somehow it's worse than polling.
Here's some additional reading on using interrupts:
https://daq00.triumf.ca/MidasWiki/index.php/Frontend_user_code
For the parallel port PCIe card.
I downlaoded the drivers here:
https://www.startech.com/en-us/cards-adapters/pex1s1p950
In there was a pdf "PEX1P2 DIG.pdf" that was useful.
PEX1P2 DIG.pdf
I followed those instructions and noticed I didn't see the card in lscpi -v
as described. I swapped the PCIe ports of the meineberg and the parallel port PCIe cards and found that the port was the issue; afterwards I didn't see the meinberg but I saw the parrallel port. I'm not sure why this is. I've taken the meinberg card out to avoid further confusion.
The pdf says to look at this information in lspci -v
:
02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284]) Subsystem: Device a000:2000 Flags: fast devsel, IRQ 5 I/O ports at e010 [disabled] [size=8] I/O ports at e000 [disabled] [size=8] Memory at fbb01000 (32-bit, non-prefetchable) [disabled] [size=4K] Memory at fbb00000 (32-bit, non-prefetchable) [disabled] [size=4K] Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+ Capabilities: [78] Power Management version 3 Capabilities: [80] Express Legacy Endpoint, MSI 00 Capabilities: [100] Advanced Error Reporting
02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284])
Subsystem: Device a000:2000
Flags: fast devsel, IRQ 5
I/O ports at e010 [disabled] [size=8]
I/O ports at e000 [disabled] [size=8]
Memory at fbb01000 (32-bit, non-prefetchable) [disabled] [size=4K]
Memory at fbb00000 (32-bit, non-prefetchable) [disabled] [size=4K]
Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [78] Power Management version 3
Capabilities: [80] Express Legacy Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
I'm pretty confident that the I/O ports should not say "disabled." I'm unsure why this is happening.
Specifically:
I/O ports at e010 [disabled] [size=8] I/O ports at e000 [disabled] [size=8]
I/O ports at e010 [disabled] [size=8]
I/O ports at e000 [disabled] [size=8]
And then use that information to run this command:
sudo modprobe parport_pc io=0xe010
sudo modprobe parport_pc io=0xe010
There are no complaints, but I don't know which of these is the correct lp port (if any)
[root@localhost ~]# ls /dev | grep "lp" lp0 lp1 lp2 lp3 [root@localhost ~]#
[root@localhost ~]# ls /dev | grep "lp"
lp0
lp1
lp2
lp3
[root@localhost ~]#
I tried looking at dmesg, but it's unclear what is going on here (this output occurs rigtht after command sudo modprobe parport_pc io=0xe010
)
[root@localhost ~]# dmesg | grep parport [ 279.843630] parport 0xe010 (WARNING): CTR: wrote 0x0c, read 0xff [ 279.843636] parport 0xe010 (WARNING): DATA: wrote 0xaa, read 0xff [ 279.843638] parport 0xe010: You gave this address, but there is probably no parallel port there! [ 279.843652] parport0: PC-style at 0xe010, irq 0 [PCSPP,TRISTATE] [ 279.843659] genirq: Flags mismatch irq 0. 00000000 (parport0) vs. 00015a20 (timer) [ 279.843692] [<ffffffffc0d7fd90>] ? parport_register_device+0x2d0/0x2d0 [parport] [ 279.843700] [<ffffffffc0d92d1a>] parport_pc_probe_port+0x61a/0xab0 [parport_pc] [ 279.843704] [<ffffffffc0d9a0e7>] ? parport_parse_param.constprop.11+0xe7/0xe7 [parport_pc] [ 279.843707] [<ffffffffc0d9a319>] parport_pc_init+0x232/0xf19 [parport_pc] [ 279.843711] [<ffffffffc0d9a0e7>] ? parport_parse_param.constprop.11+0xe7/0xe7 [parport_pc] [ 279.843734] parport0: irq 0 in use, resorting to polled operation
[root@localhost ~]# dmesg | grep parport
[ 279.843630] parport 0xe010 (WARNING): CTR: wrote 0x0c, read 0xff
[ 279.843636] parport 0xe010 (WARNING): DATA: wrote 0xaa, read 0xff
[ 279.843638] parport 0xe010: You gave this address, but there is probably no parallel port there!
[ 279.843652] parport0: PC-style at 0xe010, irq 0 [PCSPP,TRISTATE]
[ 279.843659] genirq: Flags mismatch irq 0. 00000000 (parport0) vs. 00015a20 (timer)
[ 279.843692] [<ffffffffc0d7fd90>] ? parport_register_device+0x2d0/0x2d0 [parport]
[ 279.843700] [<ffffffffc0d92d1a>] parport_pc_probe_port+0x61a/0xab0 [parport_pc]
[ 279.843704] [<ffffffffc0d9a0e7>] ? parport_parse_param.constprop.11+0xe7/0xe7 [parport_pc]
[ 279.843707] [<ffffffffc0d9a319>] parport_pc_init+0x232/0xf19 [parport_pc]
[ 279.843711] [<ffffffffc0d9a0e7>] ? parport_parse_param.constprop.11+0xe7/0xe7 [parport_pc]
[ 279.843734] parport0: irq 0 in use, resorting to polled operation
I also tried checking each 'lp' in /dev, but I'm not really sure what output I should see:
[root@localhost ~]# udevadm info -a -p /dev/lp0 syspath not found [root@localhost ~]# udevadm info -a -p /dev/lp1 syspath not found [root@localhost ~]# udevadm info -a -p /dev/lp2 syspath not found [root@localhost ~]# udevadm info -a -p /dev/lp3 syspath not found
[root@localhost ~]# udevadm info -a -p /dev/lp0
syspath not found
[root@localhost ~]# udevadm info -a -p /dev/lp1
syspath not found
[root@localhost ~]# udevadm info -a -p /dev/lp2
syspath not found
[root@localhost ~]# udevadm info -a -p /dev/lp3
syspath not found
It seems like I have to somehow get the parallel controller I/O ports and memory to not be disabled.
The readme (readme.txt) mentions
Loading the Driver: ------------------- To load the driver use the following command: $ insmod ax99100.ko ** '$' --this symbol represent the shell prompt on linux Unloading the Driver: --------------------- To unload the driver use the following command: $rmmod ax99100 ** '$' --this symbol represent the shell prompt on linux
Loading the Driver:
-------------------
To load the driver use the following command:
$ insmod ax99100.ko
** '$' --this symbol represent the shell prompt on linux
Unloading the Driver:
---------------------
To unload the driver use the following command:
$rmmod ax99100
** '$' --this symbol represent the shell prompt on linux
which was actually the first thing I did. I tried unloading the driver, rebooting, and repeating the steps in the pdf above, but no luck.
I additionally found these steps in the readme.
Steps for setting parallel port : --------------------------------- 1. rmmod lp 2. rmmod parport_pc 2. insmod parport_pc.ko io=bar0 io_hi=bar1 irq=number. Note: Here, the io, io_hi and irq should be noted from lspci -v.
Steps for setting parallel port :
---------------------------------
1. rmmod lp
2. rmmod parport_pc
2. insmod parport_pc.ko io=bar0 io_hi=bar1 irq=number.
Note: Here, the io, io_hi and irq should be noted from lspci -v.
So I tried using this information:
02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284]) Subsystem: Device a000:2000 Flags: fast devsel, IRQ 5 I/O ports at e010 [disabled] [size=8] I/O ports at e000 [disabled] [size=8] Memory at fbb01000 (32-bit, non-prefetchable) [disabled] [size=4K] Memory at fbb00000 (32-bit, non-prefetchable) [disabled] [size=4K] Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+ Capabilities: [78] Power Management version 3 Capabilities: [80] Express Legacy Endpoint, MSI 00 Capabilities: [100] Advanced Error Reporting
02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284])
Subsystem: Device a000:2000
Flags: fast devsel, IRQ 5
I/O ports at e010 [disabled] [size=8]
I/O ports at e000 [disabled] [size=8]
Memory at fbb01000 (32-bit, non-prefetchable) [disabled] [size=4K]
Memory at fbb00000 (32-bit, non-prefetchable) [disabled] [size=4K]
Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [78] Power Management version 3
Capabilities: [80] Express Legacy Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
I'm not sure what io
and io_hi
should be. I tried both:
insmod parport_pc.ko io=0xe010 io_hi=0xe000 irq=5
insmod parport_pc.ko io=0xe010 io_hi=0xe000 irq=5
which takes io_hi
to be the second I/O port BAR, and
insmod parport_pc.ko io=0xe010 io_hi=0xe050 irq=5
insmod parport_pc.ko io=0xe010 io_hi=0xe050 irq=5
which adds 8 bytes (the size) listed above to the io
BAR.
All of these (and more dumb ideas I tried) seem to result in:
[root@localhost AX99100_SP_PP_SPI_Linux_Driver_v1.8.0_Source]# insmod parport_pc.ko io=0xe010 io_hi=0xe000 irq=5 insmod: ERROR: could not insert module parport_pc.ko: Unknown symbol in module
[root@localhost AX99100_SP_PP_SPI_Linux_Driver_v1.8.0_Source]# insmod parport_pc.ko io=0xe010 io_hi=0xe000 irq=5
insmod: ERROR: could not insert module parport_pc.ko: Unknown symbol in module
At first I thought it was a kernel version issue, but the readme claims no issue:
Kernels: -------- This driver is currently developed and tested on 2.6.13 linux kernel and above
Kernels:
--------
This driver is currently developed and tested on 2.6.13 linux kernel and above
as our kernel version is much higher:
[root@localhost AX99100_SP_PP_SPI_Linux_Driver_v1.8.0_Source]# uname -r 3.10.0-1160.99.1.el7.x86_64
[root@localhost AX99100_SP_PP_SPI_Linux_Driver_v1.8.0_Source]# uname -r
3.10.0-1160.99.1.el7.x86_64
This is the procedureI followed after installing the driver (see above pdf) to "activate" the card:
echo 1 | sudo tee /sys/bus/pci/devices/0000:02:00.2/enable
echo 1 | sudo tee /sys/bus/pci/devices/0000:02:00.2/enable
lspci -v | grep -A 10 "02:00.2"
lspci -v | grep -A 10 "02:00.2"
[root@localhost ~]# lspci -v | grep -A 10 "02:00.2" 02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284]) Subsystem: Device a000:2000 Flags: fast devsel, IRQ 48 I/O ports at e010 [size=8] I/O ports at e000 [size=8] Memory at fbb01000 (32-bit, non-prefetchable) [size=4K] Memory at fbb00000 (32-bit, non-prefetchable) [size=4K] Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+ Capabilities: [78] Power Management version 3 Capabilities: [80] Express Legacy Endpoint, MSI 00 Capabilities: [100] Advanced Error Reporting
[root@localhost ~]# lspci -v | grep -A 10 "02:00.2"
02:00.2 Parallel controller: Asix Electronics Corporation Device 9100 (prog-if 03 [IEEE1284])
Subsystem: Device a000:2000
Flags: fast devsel, IRQ 48
I/O ports at e010 [size=8]
I/O ports at e000 [size=8]
Memory at fbb01000 (32-bit, non-prefetchable) [size=4K]
Memory at fbb00000 (32-bit, non-prefetchable) [size=4K]
Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [78] Power Management version 3
Capabilities: [80] Express Legacy Endpoint, MSI 00
Capabilities: [100] Advanced Error Reporting
sudo modprobe -r parport_pc sudo modprobe parport_pc io=0xe010 irq=48
sudo modprobe -r parport_pc
sudo modprobe parport_pc io=0xe010 irq=48
dmesg
shows no issues:[root@localhost ~]# dmesg | grep parport [ 276.465148] parport0: PC-style at 0xe010, irq 48 [PCSPP,TRISTATE,EPP] [root@localhost ~]#
[root@localhost ~]# dmesg | grep parport
[ 276.465148] parport0: PC-style at 0xe010, irq 48 [PCSPP,TRISTATE,EPP]
[root@localhost ~]#
parport0
in devices:[root@localhost ~]# ls /dev/parport0 /dev/parport0
[root@localhost ~]# ls /dev/parport0
/dev/parport0
[root@localhost ~]# udevadm info -q path -n /dev/parport0 /devices/platform/parport_pc.57360/ppdev/parport0 [root@localhost ~]# udevadm info -a -p /devices/platform/parport_pc.57360/ppdev/parport0 Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device. looking at device '/devices/platform/parport_pc.57360/ppdev/parport0': KERNEL=="parport0" SUBSYSTEM=="ppdev" DRIVER=="" looking at parent device '/devices/platform/parport_pc.57360': KERNELS=="parport_pc.57360" SUBSYSTEMS=="platform" DRIVERS=="parport_pc" looking at parent device '/devices/platform': KERNELS=="platform" SUBSYSTEMS=="" DRIVERS=="" [root@localhost ~]#
[root@localhost ~]# udevadm info -q path -n /dev/parport0
/devices/platform/parport_pc.57360/ppdev/parport0
[root@localhost ~]# udevadm info -a -p /devices/platform/parport_pc.57360/ppdev/parport0
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/platform/parport_pc.57360/ppdev/parport0':
KERNEL=="parport0"
SUBSYSTEM=="ppdev"
DRIVER==""
looking at parent device '/devices/platform/parport_pc.57360':
KERNELS=="parport_pc.57360"
SUBSYSTEMS=="platform"
DRIVERS=="parport_pc"
looking at parent device '/devices/platform':
KERNELS=="platform"
SUBSYSTEMS==""
DRIVERS==""
[root@localhost ~]#
Apparently doing above was not enough. I tried changinging the code for MasterGM2/frontend.cpp
/* configure parallel port */ if (trigger_source == PP) { /* open trigger device */ const char *fd_name = "/dev/trigger"; printf("Connecting to [%s] ...", fd_name); fd_pp = open("/dev/trigger", O_RDWR); // for DAQ enable output if (fd_pp < 0) { cm_msg(MERROR, "frontend_init", "Error opening file [%s]", fd_name); return FE_ERR_HW; } printf(" done PP configure \n"); }
/* configure parallel port */
if (trigger_source == PP) {
/* open trigger device */
const char *fd_name = "/dev/trigger";
printf("Connecting to [%s] ...", fd_name);
fd_pp = open("/dev/trigger", O_RDWR); // for DAQ enable output
if (fd_pp < 0) {
cm_msg(MERROR, "frontend_init", "Error opening file [%s]", fd_name);
return FE_ERR_HW;
}
printf(" done PP configure \n");
}
to
/* configure parallel port */ if (trigger_source == PP) { /* open trigger device */ const char *fd_name = "/dev/parport0"; printf("Connecting to [%s] ...", fd_name); fd_pp = open("/dev/parport0", O_RDWR); // for DAQ enable output if (fd_pp < 0) { cm_msg(MERROR, "frontend_init", "Error opening file [%s]", fd_name); return FE_ERR_HW; } printf(" done PP configure \n"); }
/* configure parallel port */
if (trigger_source == PP) {
/* open trigger device */
const char *fd_name = "/dev/parport0";
printf("Connecting to [%s] ...", fd_name);
fd_pp = open("/dev/parport0", O_RDWR); // for DAQ enable output
if (fd_pp < 0) {
cm_msg(MERROR, "frontend_init", "Error opening file [%s]", fd_name);
return FE_ERR_HW;
}
printf(" done PP configure \n");
}
It didn't complain when initializing (but I'm pretty sure it wouldn't complain as long as you gave it a valid filepath at this point).
I was able to start a run but saw no events from the master (and no errors). Ending a run gave this error:
01:55:35.682 2024/05/24 [mhttpd,INFO] Run #230 stopped 01:55:32.464 2024/05/24 [MasterGM2,ERROR] [frontend.cpp:1312:end_of_run,ERROR] Error writing to parallel port 01:55:32.464 2024/05/24 [MasterGM2,INFO] End of Run: fills registered by all frontends match! 01:55:32.464 2024/05/24 [MasterGM2,INFO] End of Run: DC7 Triggers Received 16081 Count triggers 0 01:55:01.711 2024/05/24 [mhttpd,INFO] Run #230 started
01:55:35.682 2024/05/24 [mhttpd,INFO] Run #230 stopped
01:55:32.464 2024/05/24 [MasterGM2,ERROR] [frontend.cpp:1312:end_of_run,ERROR] Error writing to parallel port
01:55:32.464 2024/05/24 [MasterGM2,INFO] End of Run: fills registered by all frontends match!
01:55:32.464 2024/05/24 [MasterGM2,INFO] End of Run: DC7 Triggers Received 16081 Count triggers 0
01:55:01.711 2024/05/24 [mhttpd,INFO] Run #230 started
It seems apparent that poll( &pfds, 1, timeout)
in this part of the code:
if(trigger_source==PP){ pfds.fd = fd_pp; pfds.events = POLLIN; int timeout = 10; int ret = 0; ret = poll( &pfds, 1, timeout); if ( ret > 0 ) {
if(trigger_source==PP){
pfds.fd = fd_pp;
pfds.events = POLLIN;
int timeout = 10;
int ret = 0;
ret = poll( &pfds, 1, timeout);
if ( ret > 0 )
{
is returning less than 1 every time. I.e. the polling is probably timing out.
To test out the paralllel port, I got chatGPT to write some C code (placed in /home/playground/parallel_port/parallel_port_test) that supposedly reads and writes to it:
parallel_port_test.c
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/ppdev.h> int main() { int fd = open("/dev/parport0", O_RDWR); if (fd == -1) { perror("Cannot open /dev/parport0"); return 1; } if (ioctl(fd, PPEXCL) < 0) { perror("Could not lock port"); close(fd); return 1; } if (ioctl(fd, PPCLAIM) < 0) { perror("Could not claim port"); close(fd); return 1; } char write_data = 0xFF; // Data to send printf("Writing data: 0x%02X\n", (unsigned char)write_data); if (ioctl(fd, PPWDATA, &write_data) < 0) { perror("Could not write data"); close(fd); return 1; } else { printf("Data written successfully\n"); } char read_data; if (ioctl(fd, PPRSTATUS, &read_data) < 0) { perror("Could not read data"); close(fd); return 1; } printf("Data read: 0x%02X\n", read_data); if (read_data == write_data) { printf("Readback matches write operation.\n"); } else { printf("Readback does not match write operation.\n"); } ioctl(fd, PPRELEASE); close(fd); return 0; }
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
int main() {
int fd = open("/dev/parport0", O_RDWR);
if (fd == -1) {
perror("Cannot open /dev/parport0");
return 1;
}
if (ioctl(fd, PPEXCL) < 0) {
perror("Could not lock port");
close(fd);
return 1;
}
if (ioctl(fd, PPCLAIM) < 0) {
perror("Could not claim port");
close(fd);
return 1;
}
char write_data = 0xFF; // Data to send
printf("Writing data: 0x%02X\n", (unsigned char)write_data);
if (ioctl(fd, PPWDATA, &write_data) < 0) {
perror("Could not write data");
close(fd);
return 1;
} else {
printf("Data written successfully\n");
}
char read_data;
if (ioctl(fd, PPRSTATUS, &read_data) < 0) {
perror("Could not read data");
close(fd);
return 1;
}
printf("Data read: 0x%02X\n", read_data);
if (read_data == write_data) {
printf("Readback matches write operation.\n");
} else {
printf("Readback does not match write operation.\n");
}
ioctl(fd, PPRELEASE);
close(fd);
return 0;
}
Nothing fails, however, the output indicates that the write wasn't succesfful:
[root@localhost parallel_port_test]# ./parallel_port_test Writing data: 0xFF Data written successfully Data read: 0x38 Readback does not match write operation.
[root@localhost parallel_port_test]# ./parallel_port_test
Writing data: 0xFF
Data written successfully
Data read: 0x38
Readback does not match write operation.
I got ChatGPT to make me two other test scripts, both failed similarly:
parallel_port_write.c
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/ppdev.h> #include <limits.h> // Include limits.h for UCHAR_MAX #define PORT_ADDRESS "/dev/parport0" #define DEFAULT_DATA 0xFF int main(int argc, char *argv[]) { // Data to write to the parallel port (default: 0xFF) unsigned char write_data = DEFAULT_DATA; // Check if a command-line argument is provided if (argc > 1) { // Convert the argument to an integer unsigned long int parsed_data = strtoul(argv[1], NULL, 0); // Check if conversion was successful if (parsed_data <= UCHAR_MAX) { write_data = (unsigned char)parsed_data; } else { fprintf(stderr, "Error: Invalid data argument. Using default: 0x%02X\n", DEFAULT_DATA); } } // Open the parallel port int fd_pp = open(PORT_ADDRESS, O_RDWR); if (fd_pp == -1) { perror("Error opening parallel port"); return 1; } // Write data to the parallel port printf("Writing data to parallel port: 0x%02X\n", write_data); ssize_t bytes_written = write(fd_pp, &write_data, sizeof(write_data)); if (bytes_written < 0) { perror("Error writing data to parallel port"); close(fd_pp); return 1; } else if (bytes_written != sizeof(write_data)) { fprintf(stderr, "Error: Incomplete write to parallel port\n"); close(fd_pp); return 1; } printf("Data written successfully\n"); // Close the parallel port close(fd_pp); return 0; }
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
#include <limits.h> // Include limits.h for UCHAR_MAX
#define PORT_ADDRESS "/dev/parport0"
#define DEFAULT_DATA 0xFF
int main(int argc, char *argv[]) {
// Data to write to the parallel port (default: 0xFF)
unsigned char write_data = DEFAULT_DATA;
// Check if a command-line argument is provided
if (argc > 1) {
// Convert the argument to an integer
unsigned long int parsed_data = strtoul(argv[1], NULL, 0);
// Check if conversion was successful
if (parsed_data <= UCHAR_MAX) {
write_data = (unsigned char)parsed_data;
} else {
fprintf(stderr, "Error: Invalid data argument. Using default: 0x%02X\n", DEFAULT_DATA);
}
}
// Open the parallel port
int fd_pp = open(PORT_ADDRESS, O_RDWR);
if (fd_pp == -1) {
perror("Error opening parallel port");
return 1;
}
// Write data to the parallel port
printf("Writing data to parallel port: 0x%02X\n", write_data);
ssize_t bytes_written = write(fd_pp, &write_data, sizeof(write_data));
if (bytes_written < 0) {
perror("Error writing data to parallel port");
close(fd_pp);
return 1;
} else if (bytes_written != sizeof(write_data)) {
fprintf(stderr, "Error: Incomplete write to parallel port\n");
close(fd_pp);
return 1;
}
printf("Data written successfully\n");
// Close the parallel port
close(fd_pp);
return 0;
}
parallel_port_poll.c
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/poll.h> // Include poll header #define PORT_ADDRESS "/dev/parport0" // Adjust the port address as per your system int main() { // Open the parallel port int fd_pp = open(PORT_ADDRESS, O_RDONLY); // Open in read-only mode for polling if (fd_pp == -1) { perror("Cannot open parallel port"); return 1; } // Set up the pollfd structure struct pollfd pfds; pfds.fd = fd_pp; // File descriptor to poll pfds.events = POLLIN; // Events to monitor (in this case, POLLIN for input data) int timeout = 10; // Timeout value in milliseconds // Perform polling int ret = poll(&pfds, 1, timeout); if (ret == -1) { perror("poll"); close(fd_pp); return 1; } else if (ret == 0) { printf("Timeout occurred\n"); } else { // Check if POLLIN event occurred if (pfds.revents & POLLIN) { printf("Data available for reading from parallel port\n"); // Read data from the parallel port if needed unsigned char data; if (read(fd_pp, &data, sizeof(data)) < 0) { perror("Error reading data from parallel port"); } else { printf("Data read from parallel port: 0x%02X\n", data); } } else { printf("Unexpected event occurred\n"); } } // Close the parallel port close(fd_pp); return 0; }
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/poll.h> // Include poll header
#define PORT_ADDRESS "/dev/parport0" // Adjust the port address as per your system
int main() {
// Open the parallel port
int fd_pp = open(PORT_ADDRESS, O_RDONLY); // Open in read-only mode for polling
if (fd_pp == -1) {
perror("Cannot open parallel port");
return 1;
}
// Set up the pollfd structure
struct pollfd pfds;
pfds.fd = fd_pp; // File descriptor to poll
pfds.events = POLLIN; // Events to monitor (in this case, POLLIN for input data)
int timeout = 10; // Timeout value in milliseconds
// Perform polling
int ret = poll(&pfds, 1, timeout);
if (ret == -1) {
perror("poll");
close(fd_pp);
return 1;
} else if (ret == 0) {
printf("Timeout occurred\n");
} else {
// Check if POLLIN event occurred
if (pfds.revents & POLLIN) {
printf("Data available for reading from parallel port\n");
// Read data from the parallel port if needed
unsigned char data;
if (read(fd_pp, &data, sizeof(data)) < 0) {
perror("Error reading data from parallel port");
} else {
printf("Data read from parallel port: 0x%02X\n", data);
}
} else {
printf("Unexpected event occurred\n");
}
}
// Close the parallel port
close(fd_pp);
return 0;
}
With outputs:
[root@localhost parallel_port_test]# ./parallel_port_write 0xAA Writing data to parallel port: 0xAA Error writing data to parallel port: Invalid argument [root@localhost parallel_port_test]# ./parallel_port_poll Timeout occurred [root@localhost parallel_port_test]#
[root@localhost parallel_port_test]# ./parallel_port_write 0xAA
Writing data to parallel port: 0xAA
Error writing data to parallel port: Invalid argument
[root@localhost parallel_port_test]# ./parallel_port_poll
Timeout occurred
[root@localhost parallel_port_test]#
These two files try to more closely mimic the function calls present in MasterGM2/frontend.cpp
I'm fairly confident /dev/parport0
is the correct path because it dissapears with command:
sudo modprobe -r parport_pc
sudo modprobe -r parport_pc
and reappears with command:
sudo modprobe parport_pc io=0xe010 irq=48
sudo modprobe parport_pc io=0xe010 irq=48
Interestingly, I don't need to include irq=48
to make /dev/parport0
appear. I'm not sure if this is meaningful.
In any event, the result of the scripts and launching the frontends is no different whether I use
sudo modprobe parport_pc io=0xe010 irq=48
sudo modprobe parport_pc io=0xe010 irq=48
or
sudo modprobe parport_pc io=0xe010
sudo modprobe parport_pc io=0xe010
to load the module.
But I do notice MasterGM2/frontend causes this output when loading the module in the second case:
Message from syslogd@localhost at May 24 02:50:47 ... kernel:Disabling IRQ #18
Message from syslogd@localhost at May 24 02:50:47 ...
kernel:Disabling IRQ #18
it occurs system wide, I saw it occur in another shell session ssh'd into the computer that was not running the frontend.
I also notice this error at the beginning of a run:
Error: Write to parallel port failed! Data 0x007f [MasterGM2,ERROR] [frontend.cpp:1112:begin_of_runfe_loop,ERROR] Error writing to parallel port begin_of_run: write datum 0x7f
Error: Write to parallel port failed! Data 0x007f
[MasterGM2,ERROR] [frontend.cpp:1112:begin_of_runfe_loop,ERROR] Error writing to parallel port
begin_of_run: write datum 0x7f
That is not critical to the run starting. It happens whether I do sudo modprobe parport_pc io=0xe010 irq=48
or sudo modprobe parport_pc io=0xe010